package com.gitee.zihaolicn;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

/**
 * 并行搜索 .class 文件工具
 */
public final class ClassFileFinder {

    /**
     * 对外同步接口：给定根目录，返回所有 .class 文件的绝对路径（已去重、不可变）
     */
    public static List<Path> findClassFiles(String rootDir) throws IOException {
        Path start = Paths.get(rootDir);
        if (!Files.isDirectory(start)) {
            throw new IllegalArgumentException("Not a directory: " + rootDir);
        }

        // ForkJoinPool 的并行度默认 = CPU 核心数
        ForkJoinPool pool = ForkJoinPool.commonPool();
        Collector collector = new Collector(start);
        pool.invoke(collector);
        return Collections.unmodifiableList(collector.result);
    }

    /* -------------------------------------------------- */

    // 自定义 Visitor，真正干活的地方
    private static final class CollectVisitor extends SimpleFileVisitor<Path> {
        private final PathMatcher matcher =
                FileSystems.getDefault().getPathMatcher("glob:**.pdf");
        private final List<Path> sink;

        CollectVisitor(List<Path> sink) {
            this.sink = sink;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
            if (attrs.isRegularFile() && matcher.matches(file)) {
                synchronized (sink) {
                    sink.add(file.toAbsolutePath());
                }
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) {
            // 出错时忽略，继续走
            return FileVisitResult.CONTINUE;
        }
    }

    // ForkJoinTask：以目录为单位拆分并行任务
    private static final class Collector extends RecursiveAction {
        private final Path dir;
        private final List<Path> result = Collections.synchronizedList(new ArrayList<>());

        Collector(Path dir) {
            this.dir = dir;
        }

        @Override
        protected void compute() {
            try {
                List<Collector> subTasks = new ArrayList<>();
                // walkFileTree 本身是非递归的 API，我们只用它扫描当前目录一层
                Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult preVisitDirectory(Path subDir, BasicFileAttributes attrs) {
                        if (!subDir.equals(dir)) { // 只把 *子目录* 提交给 Fork/Join
                            Collector child = new Collector(subDir);
                            child.fork();
                            subTasks.add(child);
                            return FileVisitResult.SKIP_SUBTREE; // 不再深入
                        }
                        return FileVisitResult.CONTINUE;
                    }

                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                        new CollectVisitor(result).visitFile(file, attrs);
                        return FileVisitResult.CONTINUE;
                    }

                    @Override
                    public FileVisitResult visitFileFailed(Path file, IOException exc) {
                        return FileVisitResult.CONTINUE;
                    }
                });

                // 等待所有子任务完成
                for (Collector task : subTasks) {
                    task.join();
                    result.addAll(task.result);
                }
            } catch (IOException e) {
                // 简单处理：打印并继续
                e.printStackTrace();
            }
        }
    }

    /* -------------------------------------------------- */
    // 快速测试
    public static void main(String[] args) throws IOException {

        List<Path> list = findClassFiles("E:\\下载");
        list.forEach(System.out::println);
        System.out.println("Total: " + list.size() + " files.");
    }
}